/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.commons.event;

import io.iec.edp.caf.commons.event.entity.MethodDelegate;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;


/**
 * 事件句柄集合类
 * 当一个类中定义了多个事件时,分别定义时会显得繁琐
 * 本类将多个事件包到一个HashMap中,封装了多个事件的一致性操作
 */

public class EventHandlerSet {

    private Map<Object , List<MethodDelegate>> eventsMap=new HashMap<>();

    /**
     * 增加要执行的事件
     * @param listener 要执行方法的对象
     * @param methodName 要执行的方法名
     */
    public void addHandler(Object eventkey, IEventListener listener, String methodName){
        if(this.eventsMap.containsKey(eventkey)){          //实现同一个eventKey的累加
            List<MethodDelegate> methodDelegateList=this.eventsMap.get(eventkey);
            methodDelegateList.add(new MethodDelegate(listener,methodName));
            this.eventsMap.put(eventkey,methodDelegateList);
        }else {
            List<MethodDelegate> methodDelegateList=new ArrayList<>();
            methodDelegateList.add(new MethodDelegate(listener,methodName));
            this.eventsMap.put(eventkey,methodDelegateList);
        }
    }

    /**
     * 删除要执行的事件
     * @param listener  要执行方法的对象
     * @param methodName 要执行的方法名
     */
    public void removeHandler(Object eventkey, IEventListener listener, String methodName){
        List<MethodDelegate> methodDelegateList=this.eventsMap.get(eventkey);
        for(int i=0;i<methodDelegateList.size();i++){  //查找对应的delegate,并将其删除
            MethodDelegate delegate=methodDelegateList.get(i);
            if(delegate.getListener().getClass()==listener.getClass()&&methodName.equals(delegate.getMethodName())){
                methodDelegateList.remove(i);
            }
            break;
        }

        //若eventKey对应的List<MethodDelegate>的大小为0,便将此eventKey从map中删除
        if(methodDelegateList.size()==0){
            this.eventsMap.remove(eventkey);
        }else {
            this.eventsMap.put(eventkey,methodDelegateList);
        }
    }

    /**
     * 激发特定的事件
     * @param eventKey 事件类型的Key值
     * @param e 事件参数
     */
    public void fire(Object eventKey, CAFEventArgs e){
        if(!eventsMap.containsKey(eventKey)){
            return;
        }

        for(MethodDelegate methodDelegate :eventsMap.get(eventKey)) {
            //判断delegate中参数类型是否与e的类型一致，一致就触发
            methodDelegate.invoke(e);
        }
    }

    /**
     * 清除eventsMap
     */
    public void dispose(){
        this.eventsMap=null;
    }

    /**
     * 创建EventHandlerSet的线程封装对象并返回
     * @param eventHandlerSet 参数
     * @return EventHandlerSet的线程封装对象
     */
    public static EventHandlerSet synchronizedSet(EventHandlerSet eventHandlerSet){
        if(eventHandlerSet==null){
            throw new IllegalArgumentException("eventHandlerSet cannot be null");
        }
        return new SynchronizedEventHandlerSet(eventHandlerSet);
    }

    /**
     * 内部类 继承EventHandlerSet
     */
    private  static class SynchronizedEventHandlerSet extends EventHandlerSet {
        private EventHandlerSet eventHandlerSet;
        private ReadWriteLock lock;

        /**
         * 构造函数
         * @param eventHandlerSet
         */
        public SynchronizedEventHandlerSet(EventHandlerSet eventHandlerSet){
            this.eventHandlerSet=eventHandlerSet;
            this.lock=new ReentrantReadWriteLock();
            dispose();
        }

        /**
         * 重写addHandler()方法
         * @param eventkey
         * @param listener 要执行方法的对象
         * @param methodName 要执行的方法名
         */
        public void addHandler(Object eventkey,IEventListener listener,String methodName){
            lock.writeLock().lock();
            try{
                eventHandlerSet.addHandler(eventkey,listener,methodName);
            }finally {
                lock.writeLock().unlock();
            }
        }

        /**
         * 重写removeHandler方法
         * @param eventkey
         * @param listener  要执行方法的对象
         * @param methodName 要执行的方法名
         */
        public void removeHandler(Object eventkey,IEventListener listener,String methodName){
            lock.writeLock().lock();
            try{
                eventHandlerSet.removeHandler( eventkey,listener,methodName);
            }finally {
                lock.writeLock().unlock();
            }
        }

        /**
         * 重写fire方法
         * @param eventKey 事件类型的Key值
         * @param e 事件
         */
        public void fire(Object eventKey,CAFEventArgs e){
            lock.readLock().lock();
            try{
                eventHandlerSet.fire(eventKey,e);
            }finally {
                lock.readLock().unlock();
            }
        }
    }
}
